from flask import current_app,session,request,g,jsonify
from iHome.models import Facility, HouseImage
from iHome.utils.qiniu_storage import storage
import logging,datetime
from iHome import db,constants,redis_store
from iHome.models import House, Order,Area
from iHome.utils.commony import login_required
from iHome.utils.response_code import RET
from . import house_blu # 蓝图对象


@house_blu.route("/houses/index")
@login_required
def house_index():
    """主页幻灯片"""

    # 判断是否登录
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 读取缓存
    try:
        houses_info = redis_store.get("home_page_house_info")
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='缓存获取失败')

    # 判断内容是否存在
    if houses_info:
        return jsonify(errno=RET.OK, errmsg='为你展示中', data=houses_info)

    # 查询5条房源信息并且销量最高的前五条
    try:
        houses = House.query.order_by(House.order_count.desc()).limit(constants.HOME_PAGE_MAX_HOUSES)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    if not houses:
        return jsonify(errno=RET.NODATA, errmsg='未查到该房源')

    # 交易量前五个房源
    houses_list = []
    for houses in houses:
        houses_list.append(houses.to_basic_dict())
    print(houses_list)

    # 把houses_list数据缓存到redis
    try:
        redis_store.setex("home_page_house_info", constants.HOME_PAGE_DATA_REDIS_EXPIRES, houses_list)
    except Exception as e:
        logging.error(e)

    return jsonify(errno=RET.OK, errmsg='为你展示中', data=houses_list)

#-----------------------------------------------------------------------------------------------------------------

@house_blu.route("/user/houses")
@login_required
def houses_list():
    """用户的房屋列表"""

    # 判断是否登录
    user_id = g.user_id
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 查找该房主名下的房屋对象
    house_object_list=House.query.filter(House.user_id == user_id).order_by(House.create_time.desc()).all()

    # 获取所需信息，拼成data,返回给前端页面
    house_list=[]
    for house in house_object_list:
        house_list.append(house.to_basic_dict())

    return jsonify(errno=RET.OK,errmsg="获取房源列表成功",data=house_list)
#-----------------------------------------------------------------------------------------------------------------

@house_blu.route("/houses",methods=["POST"])
@login_required
def save_new_house():
    """发布新房源"""

    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    # 实名认证
    if user.id_card == None:
        return jsonify(errno=RET.SESSIONERR, errmsg='还未注册')

    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg='用户不存在')

    # 获取参数
    # 房屋参数
    data_dict=request.json
    title=data_dict.get("title")
    price=data_dict.get("price")
    area_id=data_dict.get("area_id")
    address=data_dict.get("address")
    room_count=data_dict.get("room_count")
    acreage=data_dict.get("acreage")
    unit=data_dict.get("unit")
    capacity=data_dict.get("capacity")
    beds=data_dict.get("beds")
    deposit=data_dict.get("deposit")
    min_days=data_dict.get("min_days")
    max_days=data_dict.get("max_days")

    if not all([title,price,area_id,address,room_count,acreage,unit,capacity,beds,deposit,min_days,max_days]):
        return jsonify(errno=RET.PARAMERR,errmsg="参数不全")

    # 检测数值不能为负
    listnum = [int(price), int(room_count), int(acreage), int(capacity), int(beds), int(deposit), int(min_days),
               int(max_days)]
    for num in listnum:
        if num < 0:
            return jsonify(errno=RET.PARAMERR, errmsg="数值不能为负")

    # 创建房源信息
    house=House()
    house.user_id=user.id
    house.area_id=area_id
    house.title=title
    house.price=float(price)*100
    house.address=address
    house.room_count=room_count
    house.acreage=acreage
    house.unit=unit
    house.capacity=capacity
    house.beds=beds
    house.deposit=deposit
    house.min_days=min_days
    house.max_days=max_days

    # checkbox参数
    facility=data_dict.get("facility")
    if facility:
        try:
            facilities=Facility.query.filter(Facility.id.in_(facility)).all()
            house.facilities=facilities
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR,errmsg="数据库操作失败")

    # 提交数据库
    try:
        db.session.add(house)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="房源发布成功")

    return jsonify(errno=RET.OK,errmsg="房源发布成功",data={"house_id":house.id})

#--------------------------------------------------------------------------------------------------
#用户上传图片
@house_blu.route("/houses/<int:house_id>/images",methods=["POST"])
@login_required
def upload_image(house_id):

    # 登陆验证
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 取到图片文件
    image_file = request.files.get('house_image')
    if not image_file:
        return jsonify(errno=RET.PARAMERR, errmsg="未选择图片")

    # 尝试查询房屋数据
    try:
        house = House.query.filter_by(id=house_id).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询房屋数据失败')
    if not house:
        return jsonify(errno=RET.NODATA, errmsg='未查询到对应房屋')

    # 使用七牛上传图片
    image_data = image_file.read()
    try:
        image_name = storage(image_data)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="上传图片到七牛失败")

    # 判断房屋是否有主图片，如果没有，则设置
    if not house.index_image_url:
        house.index_image_url = image_name
        db.session.add(house)

    # 生成房屋图片模型并保存至数据数据库
    house_image = HouseImage()
    house_image.house_id = house_id
    house_image.url = image_name

    try:
        db.session.add(house_image)
        db.session.commit()
    except Exception as e:
        logging.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存房屋图片失败")

    # 返回数据
    image_url = constants.QINIU_DOMIN_PREFIX + image_name
    return jsonify(errno=RET.OK, errmsg='OK', data={'url': image_url})


#--------------------------------------------------------------------------------------------------


@house_blu.route('/areas')
def get_areas_info():
    """查询城区信息"""

    # 从缓存中获取数据
    try:
        areas = redis_store.get('area_info')
    except Exception as e:
        logging.error(e)
        areas = None

    # 如果不为空，做查询操作
    if areas:
        return jsonify(errno=RET.OK, errmsg='获取成功', data=eval(areas))

    # 从数据库取
    try:
        areas = Area.query.all()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取城区信息失败')

    # 因为查询出来全是对象实例，不能直接进行 JSON 转化，所以定义一个数组保存所有对象的字典信息
    areas_list = []
    for area in areas:
        areas_list.append(area.to_dict())

    # 存储json_areas数据到redis缓存中
    try:
        redis_store.setex('area_info', constants.AREA_INFO_REDIS_EXPIRES, areas_list)
    except Exception as e:
        logging.error(e)

    return jsonify(errno=RET.OK, errmsg='获取成功', data=areas_list)



@house_blu.route('/houses')
def house_list():
    # 获取所有的参数
    house_info = request.args
    area_id = house_info.get("aid")  # 区域编号
    start_date_str = house_info.get("sd")  # 用户想要的起始时间
    end_date_str = house_info.get("ed")  # 用户想要的结束时间
    sort_key = house_info.get("sk", "new")  # 排序关键字
    page = house_info.get("p", 1)  # 页数
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 日期转换
    try:
        start_date = None
        end_date = None
        if start_date_str:
            start_date = datetime.datetime.strptime(start_date_str, '%Y-%m-%d')
        if end_date_str:
            end_date = datetime.datetime.strptime(end_date_str, '%Y-%m-%d')
        # 如果开始时间大于或者等于结束时间，就报错
        if start_date and end_date:
            assert start_date < end_date, Exception("开始时间大于结束时间")
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 从缓存中取出房屋列表
    try:
        redis_key = "houses_%s_%s_%s_%s" % (start_date_str, end_date_str, area_id, sort_key)
        response_data = redis_store.hget(redis_key, page)
        if response_data:
            return jsonify(errno=RET.OK, errmsg="OK", data=eval(response_data))
    except Exception as e:
        current_app.logger.error(e)

    # 查询数据
    house_query = House.query

    filters = []
    # 判断是否传入城区id
    if area_id:
        filters.append(House.area_id == area_id)

    # 过滤已预订的房屋
    conflict_order = None
    try:
        if start_date and end_date:
            conflict_order = Order.query.filter(Order.begin_date <= end_date, Order.end_date >= start_date).all()
        elif start_date:
            conflict_order = Order.query.filter(Order.end_date >= start_date).all()
        elif end_date:
            conflict_order = Order.query.filter(Order.begin_date <= end_date).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据错误")

    if conflict_order:
        # 获取到有冲突的房间id
        conflict_house_id = [order.house_id for order in conflict_order]
        # 添加条件：查询出房屋不包括冲突订单中的房屋id
        filters.append(House.id.notin_(conflict_house_id))  # 房间id不在有冲突的房间里面

    # 根据筛选条件进行排序
    # TODO　个人认为操作了数据库就应该进行异常捕获
    try:
        if sort_key == "booking":  # 按预定次数来排序
            house_query = house_query.filter(*filters).order_by(House.order_count.desc())
        elif sort_key == "price-inc": # 按价格升序来排序
            house_query = house_query.filter(*filters).order_by(House.price.asc())
        elif sort_key == "price-des": # 按价格降序来排序
            house_query = house_query.filter(*filters).order_by(House.price.desc())
        else:   # 按用户发布房源的时间来排序
            house_query = house_query.filter(*filters).order_by(House.create_time.desc())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据错误")
    # 分页查询
    paginate = house_query.paginate(int(page), constants.HOUSE_LIST_PAGE_CAPACITY, False)
    # 当前页数据
    houses = paginate.items
    # 总页数
    total_page = paginate.pages
    # 将当前页数据转换成字典
    houses_dict = []
    for house in houses:
        houses_dict.append(house.to_basic_dict())

    response_data = {"total_page": total_page, "houses": houses_dict}
    try:
        redis_key = "houses_%s_%s_%s_%s" % (start_date_str, end_date_str, area_id, sort_key)
        # 创建redis管道, 支持多命令事务
        pipe = redis_store.pipeline()
        # 开启事务
        pipe.multi()
        # 设置数据
        pipe.hset(redis_key, page, response_data)
        # 设置过期时间
        pipe.expire(redis_key, constants.HOUSE_LIST_REDIS_EXPIRES)
        # 提交事务
        pipe.execute()
    except Exception as e:
        current_app.logger.error(e)



    return jsonify(errno=RET.OK, errmsg='请求成功', data=response_data)

#----------------------------------------------------------------------------------------------------
#房屋详情页
@house_blu.route("/houses/<house_id>")
@login_required
def house_detail(house_id):
    # 判断是否登陆
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 判断参数是否有值
    if not house_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')

    user_id = session.get('user_id', -1)
    # 先从redis缓存中取
    try:
        house_info = redis_store.get('house_info_' + house_id)
    except Exception as e:
        house_info = None
        logging.error(e)

    # 如果有值,那么返回数据
    if house_info:
        logging.info('get house info from redis')
        return jsonify(errno=RET.OK, errmsg='OK', data={"user_id": user_id, "house": eval(house_info)})

    # 没有从缓存中取到,查询数据)库
    house = House.query.filter_by(id=house_id).first()
    if not house:
        return jsonify(errno=RET.NODATA, errmsg='未查询到房屋信息')

    # 将数据缓存到redis中
    house_dict = house.to_full_dict()
    try:
        redis_store.setex('house_info_' + house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND, house_dict)
    except Exception as e:
        logging.error(e)

    # 订单提交 图片获取
    try:
        house_image = HouseImage.query.filter(HouseImage.house_id == house_id).all()
    except Exception as e:
        logging.error(e)

    house_image_list =[]
    for images in house_image:
        house_image_list.append(images)

    # 返回数据
    return jsonify(errno=RET.OK, errmsg='OK', data={"user_id": user_id, "house": house_dict,'house_image_url':constants.QINIU_DOMIN_PREFIX + house_image_list[0].url})


